package compile

import (
	"fmt"
	"path/filepath"
	"sail/classpath"
	"strings"
)

type ClassEntry struct {
	ClassName string
	Path      []string
}

// returns true if this class can be found through CLASSPATH
func (self *ClassEntry) exists(clsPath *classpath.ClassPath) bool {
	pathWithSep := strings.Join(self.Path, string(filepath.Separator))

	exists, err := clsPath.ClassExists(pathWithSep)
	if err != nil {
		unexpectedError(err, "")
	}

	return exists
}

type PackageEntry struct {
	EntryName string
	Children  []*PackageEntry
	Classes   []*ClassEntry
}

type WalkFunc func(*PackageEntry) error

var StopWalk = fmt.Errorf("walk stopped")

func (self *PackageEntry) Walk(walkFunc WalkFunc) error {
	err := walkFunc(self)

	if err != nil {
		if err == StopWalk {
			return nil
		} else {
			return err
		}
	}

	for _, child := range self.Children {
		err = child.Walk(walkFunc)
		if err != nil {
			if err == StopWalk {
				return nil
			} else {
				return err
			}
		}
	}

	return nil
}

func (self *PackageEntry) hasClass(className string) bool {
	for _, clsEntry := range self.Classes {
		if clsEntry.ClassName == className {
			return true
		}
	}
	return false
}

func (self *PackageEntry) getChild(childName string) *PackageEntry {
	for _, child := range self.Children {
		if child.EntryName == childName {
			return child
		}
	}
	return nil
}

func (self *PackageEntry) selfCheckAndClearUp(
	cp *classpath.ClassPath, reporter ErrorReporter) (useful bool) {

	var usefulChild []*PackageEntry

	for _, child := range self.Children {
		childUseful := child.selfCheckAndClearUp(cp, reporter)

		if childUseful {
			usefulChild = append(usefulChild, child)
		}
	}

	self.Children = usefulChild

	var usefulClassEntries []*ClassEntry

	for _, entry := range self.Classes {
		if entry.exists(cp) {
			usefulClassEntries = append(usefulClassEntries, entry)
		} else {
			reporter.Report(&Error{
				Type: "ImportError",
				Message: fmt.Sprintf("import declare (%s) can not be solved.",
					strings.Join(entry.Path, ".")),
			})
		}
	}

	self.Classes = usefulClassEntries

	if len(usefulClassEntries) == 0 && len(usefulChild) == 0 {
		return false
	}

	return true
}
